package ua.in.iticket.addressbook.userinterface;

import ua.in.iticket.addressbook.person.Address;
import ua.in.iticket.addressbook.person.Person;
import ua.in.iticket.addressbook.person.PhoneNumber;
import ua.in.iticket.addressbook.report.OfficeReport;
import ua.in.iticket.addressbook.report.ReportException;
import ua.in.iticket.addressbook.storage.FileStorage;
import ua.in.iticket.addressbook.storage.StorageException;

import java.util.*;

/**
 * Created by irina on 10.02.14.
 */
public class UIPerson implements IUserInterface  {
    //private Scanner in = new Scanner(System.in);
    final String agree = "yes";
    protected static FileStorage base;

    static {
        try {
            base = FileStorage.getStorage();
        } catch (StorageException e) {
            throw new RuntimeException(e);
        }
    }



    public PhoneNumber buildPhone(){
        Scanner in = new Scanner(System.in);
        String countryCode, operatorCode, number;
        System.out.print("Enter the countryCode: ");
        countryCode = in.next();
        System.out.print("Enter the operatorCode: ");
        operatorCode = in.next();
        System.out.print("Enter the number: ");
        number = in.next();
        return new PhoneNumber(countryCode, operatorCode, number);
    }


    public List<PhoneNumber> buildPhoneList(){
        Scanner in = new Scanner(System.in);
        String userReq = "yes";
        List <PhoneNumber> phoneList = new LinkedList<PhoneNumber>();
        do {
            phoneList.add(buildPhone());
            System.out.print("Do you want to enter next phone number? (yes/no): ");
            userReq = in.nextLine();
        } while (agree.equals(userReq));
        return phoneList;
    }

    public Address buildAdress(){
        Scanner in = new Scanner(System.in);
        String country, city, address;
        System.out.print("Enter person's country: ");
        country = in.nextLine();
        System.out.print("Enter person's city: ");
        city = in.nextLine();
        System.out.print("Enter person's address: ");
        address = in.nextLine();
        return new Address(country, city, address);
    }

    public String enterFullname(){
        Scanner in = new Scanner(System.in);
        String fullName;
        System.out.println("Enter person's fullname: ");
        fullName = in.nextLine();
        return fullName;
    }

    public int enterAge(){
        Scanner in = new Scanner(System.in);
        int age;
        System.out.println("Enter person's age: ");
        age = in.nextInt();
        return age;
    }

    public Person createPerson(){
        return new Person(enterAge(), enterFullname(), buildPhoneList(),buildAdress());
    }

    // форматированный вывод на экран для персоны
    public void printPerson(Person person) {
        StringBuilder ret = new StringBuilder();
        ret.append("Fullname: ")
                .append(person.getFullName())
                .append(System.lineSeparator())
                .append("Age: ")
                .append(person.getAge())
                .append(System.lineSeparator())
                .append("Address: ")
                .append(person.getAddress().getFullAdress())
                .append(System.lineSeparator());
        for (int i = 0; i < person.getPhoneNumbersSize(); i++) {
            ret.append("Phone №")
                    .append(i + 1)
                    .append(": ")
                    .append(person.getPhoneNumber(i).getFullNumber())
                    .append(System.lineSeparator());
        }
        System.out.println(ret.toString());
    }

    public int promptIndex(int bounds){
        Scanner in = new Scanner(System.in);
        boolean q;
        int i;
        do{
            q = false;
            System.out.print("To perform selected action enter number used in list: ");
            i = in.nextInt() - 1;
            if ((i < 0)||(i >= bounds)){
                System.out.println("The number of object must be in bounds [1.."+bounds+"]");
                q = true;
            }
        }while (q);
        return i;
    }

    // запрос на подтверждение операции
    public boolean promptAreYouSure(String message){
        Scanner in = new Scanner(System.in);
        String userReq;
        boolean ret = false;
        System.out.print(message + "(yes/no): ");
        userReq = in.nextLine();
        if (agree.equals(userReq)){ret = true; }
        return ret;
    }
    // запрос на ввод фильтра поиска персон
    public String promptFilterPerson(){
        Scanner in = new Scanner(System.in);
        System.out.print("Enter pattern to find person: ");
        return in.nextLine();
    }

    public String promptFilename(){
        Scanner in = new Scanner(System.in);
        String s = null;
        boolean ret = true;
        while (ret) {
        System.out.print("Enter name for file to output list of persons: ");
        s = in.nextLine();
        if ((s == null) || (s.length() == 0)) {
            System.out.print("Warning: Name for file to output list of persons cannot be empty! Try again.");
            ret = true;
        } else {ret = false;}
        }
        return s;
    }

    //основное меню
    public int printMenuPerson() {
        Menu menuPerson = new Menu();
        menuPerson.addItem("Create person", 1, "Use to create a new person in list");
        menuPerson.addItem("Edit person", 2, "Use to update the selected person's info: fullname, age, address, list of phone numbers.");
        menuPerson.addItem("Delete person", 3, "Use to delete the selected person in list");
        menuPerson.addItem("View", 4, "Use to find and display necessary person from your phonebook");
        menuPerson.addItem("Report", 5, "Use to output your phonebook into word or excel file");
        menuPerson.sort();
        menuPerson.printMenu();
        return menuPerson.getAction();
    }

    // подменю редактирования персоны
    public int printEditMenuPerson() {
        Menu menuEditPerson = new Menu();
        menuEditPerson.addItem("Edit fullname", 10, "Use to edit fullname for selected person");
        menuEditPerson.addItem("Edit age", 11, "Use to edit age for selected person");
        menuEditPerson.addItem("Edit address", 12, "Use to edit address for selected person");
        menuEditPerson.addItem("Add phone number", 13, "Use to add phone number for selected person");
        menuEditPerson.addItem("Edit phone number", 14, "Use to edit phone number for selected person");
        menuEditPerson.addItem("Delete phone number", 15, "Use to delete phone number for selected person");
        menuEditPerson.addItem("Delete all phone numbers", 16, "Use to edit address for selected person");
        menuEditPerson.sort();
        menuEditPerson.printMenu();
        return menuEditPerson.getAction();
    }

    // подменю вывода отчетов: ворд/ексель
    public int printReportMenu() {
        Menu menuReport = new Menu();
        menuReport.addItem("Save as a word file", 20, "Use to save your phone book as a word file");
        menuReport.addItem("Save as an excel File", 21, "Use to save your phone book as an excel file");
        menuReport.sort();
        menuReport.printMenu();
        return menuReport.getAction();
    }

    // подменю вывода персон на экрна: весь список или фильтрованный
    public int printViewMenu() {
        Menu menuReport = new Menu();
        menuReport.addItem("View all persons", 30, "Use to view all phone book");
        menuReport.addItem("View persons selected by filter", 31, "Use to view persons selected by filter");
        menuReport.sort();
        menuReport.printMenu();
        return menuReport.getAction();
    }

    // клонирование редактируемого объекта,  tmpPerson.setPid(person.getPid()) - важно!
    public Person copyPerson(Person person) {
        Address tmpAddress = new Address(person.getAddress().getCountry(), person.getAddress().getCity(), person.getAddress().getAddress());
        List<PhoneNumber> tmpPhones = new LinkedList<PhoneNumber>();
        for (int i = 0; i < person.getPhoneNumbersSize(); i++) {
            tmpPhones.add(person.getPhoneNumber(i));
        }
        Person tmpPerson = new Person(person.getAge(), person.getFullName(), tmpPhones, tmpAddress);
        tmpPerson.setPid(person.getPid());
        return tmpPerson;
    }

    // поиск по шаблону
    public List<Person> searchPerson() {
        boolean go = true;
        List<Person> list = new LinkedList<Person>();
        while (go) {
            go = false;
            String pattern = promptFilterPerson();
            list = base.getByName(pattern);
            if ((list.size() == 0) && (promptAreYouSure("Nobody is found. Try again? "))) {
                go = true;
            }
        }
        return list;
    }

   // форматированный вывод списка персон в кратком виде
   public void printPersonShort(List<Person> list) {
       if (list.size() == 0){
           System.out.println("No person in list to output");
       } else{
           for (int i = 0; i < list.size(); i++) {
               StringBuilder ret = new StringBuilder();
               Person person = list.get(i);
               ret.append(" №" + (i + 1) + ": ")
                       .append(person.getFullName())
                       .append(", ")
                       .append(person.getAge())
                       .append(" years old, ")
                       .append(person.getAddress().getFullAdress());
               for (int j = 0; j < person.getPhoneNumbersSize(); j++) {
                   ret.append(", ")
                           .append("tel-")
                           .append(j + 1)
                           .append(": ")
                           .append(person.getPhoneNumber(j).getShortNumber());
               }
               System.out.println(ret.toString());
           }
           System.out.println();
       }
   }

    // выбор в списке найденных особ
    public Person selectYourPerson() {
        Integer ind;
        List<Person> list = new LinkedList<Person>();
        Person tmpPerson = new Person();
        list = searchPerson();
        if (list.size() > 1) {
            printPersonShort(list);
            ind = promptIndex(list.size());
            tmpPerson = list.get(ind);
        } else if (list.size() == 1 ) {
            tmpPerson = list.get(0);
        } else {  return null; }
        return tmpPerson;
    }


    public Person updatePerson(Person person) {
        int opt = 0, ind;
        Person tmpPerson = copyPerson(person);
        //printPerson(person);
        while (opt != MenuConfig.MENU_EXIT_ACTION) {
            opt = printEditMenuPerson();
            switch (opt) {
                case 10:
                    tmpPerson.setFullName(enterFullname());
                    break;
                case 11:
                    tmpPerson.setAge(enterAge());
                    break;
                case 12:
                    tmpPerson.setAddress(buildAdress());
                    break;
                case 13:
                    tmpPerson.addPhone(buildPhone());
                    break;
                case 14:
                    ind = promptIndex(person.getPhoneNumbersSize());
                    tmpPerson.setPhoneNumber(ind, buildPhone());
                    break;
                case 15:
                    ind = promptIndex(person.getPhoneNumbersSize());
                    if (promptAreYouSure("Are you sure you want to delete phone number? " + tmpPerson.getPhoneNumber(ind).getFullNumber())) {
                        tmpPerson.removePhoneNumber(ind);
                    }
                    break;
                case 16:
                    if (promptAreYouSure("Are you sure you want to delete all phone numbers? ")) {
                        tmpPerson.removeAllPhoneNumber();
                    }
                    break;
            }
        }
        return tmpPerson;
    }


    public void mainMenu() throws StorageException {
        int opt = 0;
        Person person = new Person();
        while (opt !=MenuConfig.MENU_EXIT_ACTION) {
            opt = printMenuPerson();
            switch (opt){
                case 1: person = createPerson();
                    printPerson(person);
                    base.save(person);
                    base.commit();
                    break;
                case 2: person = selectYourPerson();
                    if (person != null)
                    { printPerson(person);
                        base.save(updatePerson(person));
                        base.commit();
                    }
                    break;
                case 3: person = selectYourPerson();
                    if (person != null)
                    {
                        printPerson(person);
                        if (promptAreYouSure("Are you sure you want to delete this person?")){
                            base.delete(person);
                            base.commit();
                        }
                    }
                    break;
                case 4: viewMenu();
                    break;
                case 5: reportMenu();
                    break;
            }
        }
    }

    //организация просмотра персон на экране - с фильтром и всего списка
    public void viewMenu(){
        int opt = 0;
        String fileName;
        List<Person> list = new LinkedList<Person>();
        while (opt !=MenuConfig.MENU_EXIT_ACTION) {
            opt = printViewMenu();
            switch (opt){
                case 30: list = base.getAll();
                         printPersonShort(list);
                         break;
                case 31: list = searchPerson();
                         printPersonShort(list);
                         break;

            }
        }
    }


    //вывод отчетов в ворд и эксель
    public void reportMenu(){
        int opt = 0;
        String fileName;
        OfficeReport report = new OfficeReport();
        while (opt !=MenuConfig.MENU_EXIT_ACTION) {
            opt = printReportMenu();
            switch (opt){
                case 20: fileName = promptFilename();
                    try {
                        report.TextReport(base.getAll(), fileName);
                    } catch (ReportException e) {
                        e.printStackTrace();
                    }
                    break;
                case 21: fileName = promptFilename();
                    try {
                        report.TableReport(base.getAll(), fileName);
                    } catch (ReportException e) {
                        e.printStackTrace();
                    }
                    break;

            }
        }
    }
}
